package br.ufrj.dcc.so.trab2;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.concurrent.Semaphore;

import br.ufrj.dcc.so.trab2.entity.Cliente;
import br.ufrj.dcc.so.trab2.entity.Oficial;
import br.ufrj.dcc.so.trab2.entity.Pausa;
import br.ufrj.dcc.so.trab2.entity.Praca;
import br.ufrj.dcc.so.trab2.entity.Sargento;
import br.ufrj.dcc.so.trab2.manager.BarbeiroAbstrato;
import br.ufrj.dcc.so.trab2.manager.BarbeiroOficial;
import br.ufrj.dcc.so.trab2.manager.BarbeiroPraca;
import br.ufrj.dcc.so.trab2.manager.BarbeiroSargento;
import br.ufrj.dcc.so.trab2.manager.SargentoTainha;
import br.ufrj.dcc.so.trab2.manager.TenenteEscovinha;

public class Forte {
	
	private static final int MAX_CLIENTES_GERADOS = 1000;

	private static final int MAX_CLIENTES_ESPERA = 20;
	
	private FortEventGenetator eventGenetator;
	public Barbearia barbearia;
	private SargentoTainha sargentoTainha;
	
	private BarbeiroAbstrato barbeiroOficial;
	private BarbeiroAbstrato barbeiroSargento;
	private BarbeiroAbstrato barbeiroPraca;
	
	
	private TenenteEscovinha tenenteEscovinha;
	private final Semaphore clienteDisponivel = new Semaphore(MAX_CLIENTES_ESPERA, true);
	

	public Semaphore getClienteDisponivel() {
		return clienteDisponivel;
	}

	/**
	 * Lista de clientes esperando para entrar na barbearia!
	 */
	private Iterator<Cliente> iterator; 
	
	/*
	 * Thread e sua fun��es:
	 * 
	 *  - Barbeiros: Retiram clientes das filas e atendem eles.
	 *  - SargentoTainha: Coloca os clientes em suas respectivas filas.
	 *  - TeneteEscovinha: A cada 3s adiciona uma entrada nos registros para posteriormente 
	 *  fazer o relat�rio.
	 *  
	 *  Cada Pessoa ativa o sal�o(Thread) tem acesso ao "itens" do Forte e tudo que est� dentro
	 *  inclusive a barbearia. Por isso troqui algus atributos para public
	 * 
	 */
	
	public Forte() {
		
		   
		   
		this.eventGenetator = new FortEventGeneratorImpl();
		this.iterator = criarFila();
				
		//barbearia n�o  deve ser Thread. 
		barbearia = new BarbeariaRecrutaZero(this); 

		//Cara da entrada na barbearia
		sargentoTainha = new SargentoTainha(this);
		

		barbeiroOficial = new BarbeiroOficial(barbearia);
		barbeiroSargento = new BarbeiroSargento(barbearia);
		barbeiroPraca = new BarbeiroPraca(barbearia);

		//Cara do relatório
		tenenteEscovinha = new TenenteEscovinha(this);
		
		//Dou vida ao SargentoTainha, ao teneteEscovinha e aos barbeiros
		startThreads(); 
	}

	private Iterator<Cliente> criarFila() {
		//TODO - Escrever no arquivo
		
		List<Cliente> listaClientes = new ArrayList<Cliente>();
		
		for (int i = 0; i < MAX_CLIENTES_GERADOS; i++) {
			listaClientes.add(geraCliente());
		}
		
		return listaClientes.iterator();
		
	}

	private void startThreads() {
		new Thread(sargentoTainha).start();
		new Thread(barbeiroOficial).start();  
		new Thread(barbeiroSargento).start();  
		new Thread(barbeiroPraca).start();  
		new Thread(tenenteEscovinha).start();
	}
		

	/**
	 * Gera um cliente de tipo definido randômicamente. 
	 * Onde, se há cliente, 70% são praças, 20% sargentos e 10% são Oficiais.
	 * @return Um cliente.
	 */
	public Cliente geraCliente() {
		Cliente cliente  = null;

		//Se chegou alguém, veja qual seu tipo; Se não, retorne pausa.  
		if(eventGenetator.generate()%2 == 0){
			cliente = criaCliente();
		}
		else {
			cliente = new Pausa();
		}
		return cliente;
	}

	private Cliente criaCliente() {
		Cliente cliente;
		int tipoCliente  = eventGenetator.generate()%100;
		
		int offSizeTempoServico = eventGenetator.generate()%3; // Variando entre 0 e 2
		int tempoServico = 0;
		
		if(tipoCliente <= 70){
			cliente = new Praca();
			tempoServico = 1+offSizeTempoServico; //Tempo variável entre 1 e 2.				
		}
		else {
			if(tipoCliente <=90){
				cliente = new Sargento();
				tempoServico = 2+offSizeTempoServico; //Tempo variável entre 2 e 4.
			}
			else {
				cliente = new Oficial();
				tempoServico = 4+offSizeTempoServico; //Tempo variável entre 4 e 6.
			}
		}
		
		cliente.setTempoServico(tempoServico);
		return cliente;
	}
	
	public void setEventGenetator(FortEventGenetator eventGenetator) {
		this.eventGenetator = eventGenetator;
	}

	public Cliente getProximoCliente() {
		Cliente cliente = null;
		
		if(iterator.hasNext()){
			cliente = iterator.next();
		}
		
		return cliente;
	}


}
